Using Expressions for Automation


If there is no query available to drive automation, it is possible to create your own expressions and use them to automate tasks. The expressions can be used similar to queries as described in Using Work Item Queries for Automation. As far as I can tell expressions are actually the fundamental mechanism that is used to create queries.

This post shows basic mechanisms to create expressions and to run them to get the result set back. If you are just starting with extending Rational Team Concert, start reading this and the linked posts to get some guidance on how to set up your environment.

License and how to get started with the RTC API’S

As always, our lawyers reminded me to state that the code in this post is derived from examples from Jazz.net as well as the RTC SDK. The usage of code from that example source code is governed by this license. Therefore this code is governed by this license, which basically means you can use it for internal usage, but not sell. Please also remember, as stated in the disclaimer, that this code comes with the usual lack of promise or guarantee. Enjoy!

If you just get started with extending Rational Team Concert, or create API based automation, start with the post Learning To Fly: Getting Started with the RTC Java API’s and follow the linked resources.

You should be able to use the following code in this environment and get your own automation or extension working.

To keep it simple this example is, as many others in this blog, based on the Jazz Team Wiki entry on Programmatic Work Item Creation and the Plain Java Client Library Snippets. The example in this blog shows RTC Client and Common API.

Creating an Expression

An Expression can be composed of multiple Expressions in Terms. A Term represents a Boolean operation across multiple expressions. Because I haven’t used expressions all that much I can’t describe all possible ways to use them, however, I would assume that it would be possible to create own logic for Expressions. The example below is an expression that looks for work items that are owned by a specific project area and have a specific Type (that matches an ID provided as string).

IAuditableCommon auditableCommon = (IAuditableCommon) teamRepository.getClientLibrary(IAuditableCommon.class);
IQueryableAttribute attribute = QueryableAttributes.getFactory(
	IWorkItem.ITEM_TYPE).findAttribute(projectArea,
	IWorkItem.PROJECT_AREA_PROPERTY, auditableCommon, monitor);
IQueryableAttribute type = QueryableAttributes.getFactory(
	IWorkItem.ITEM_TYPE).findAttribute(projectArea,
	IWorkItem.TYPE_PROPERTY, auditableCommon, monitor);

Expression inProjectArea = new AttributeExpression(attribute,
	AttributeOperation.EQUALS, projectArea);
Expression isType = new AttributeExpression(type,
	AttributeOperation.EQUALS, workitemTypeID);
Term typeinProjectArea= new Term(Term.Operator.AND);
typeinProjectArea.add(inProjectArea);
typeinProjectArea.add(isType);

Create a Query from an Expression

It is possible to create a query from an expression and use this as described in the post Using Work Item Queries for Automation. I have not yet found the code to save the query so that it can be used later, but this is really also not the aim of this post.

IQueryCommon queryCommon = (IQueryCommon) teamRepository.getClientLibrary(IQueryCommon.class);
IQueryDescriptor descriptor = queryCommon.createQuery(projectArea, "MyQuery", "MyQuery", typeinProjectArea);

Getting the Result Set of an Expression

It is possible to get at the result set of an expression and process it. The code below shows how. All statements about query result set size limits and running resolved and unresolved from Using Work Item Queries for Automation apply here as well.

The first method gets the result set resolved to the item profile provided.

public static IQueryResult resultsResolvedByExpression(
		ITeamRepository teamRepository, IProjectArea projectArea,
		Expression expression, ItemProfile profile)
		throws TeamRepositoryException {
	IWorkItemClient workItemClient = (IWorkItemClient) teamRepository
			.getClientLibrary(IWorkItemClient.class);
	IQueryClient queryClient = workItemClient.getQueryClient();
	IQueryResult results = queryClient
			.getResolvedExpressionResults(projectArea, expression, profile);
	return results;
}

The second method gets the unresolved result set.

public static IQueryResult resultsUnresolvedByExpression(
		ITeamRepository teamRepository, IProjectArea projectArea,
		Expression expression) throws TeamRepositoryException {
	IWorkItemClient workItemClient = (IWorkItemClient) teamRepository
			.getClientLibrary(IWorkItemClient.class);
	IQueryClient queryClient = workItemClient.getQueryClient();
	IQueryResult results = queryClient.getExpressionResults(
			projectArea, expression);
	return results;
}

Both methods are very similar to the code in Using Work Item Queries for Automation and the result sets can essentially be used the same way.

Handling Work Item States

You can use states and state groups in expressions. I found all these examples on the forum. The expression below shows the open states.

	IQueryableAttribute stateAttribute = QueryableAttributes.getFactory(
			IWorkItem.ITEM_TYPE).findAttribute(projectArea,
			IWorkItem.STATE_PROPERTY, auditableCommon, monitor);

	Expression openStates = new VariableAttributeExpression(stateAttribute,
			AttributeOperation.EQUALS, new StatusVariable(
					IWorkflowInfo.OPEN_STATES));

Sorting Results

You can use sort criteria to create a statement that has an expression as described above and add sort criteria. The criteria below sorts by work Item ID ascending.

	SortCriteria[] sortCriteria = new SortCriteria[] { new SortCriteria(
		IWorkItem.ID_PROPERTY, true) };
	Statement statement = new Statement(new SelectClause(),
		typeinProjectArea, sortCriteria);

The Wiki Page QueryDevGuide shows more example code.

As always I hope the code provided helps some RTC user to solve a problem and save some time.

Synthetic Attributes

There is information on work items that is interesting for querying where there is no real work item attribute available. For some of this information, there are synthetic attributes that you can use. Instead of  using real attributes from com.ibm.team.workitem.common.model.IWorkItem such as com.ibm.team.workitem.common.model.IWorkItem.PROJECT_AREA_PROPERTY it is possible to use synthetic attributes defined in com.ibm.team.workitem.common.query.SyntheticAttributeIdentifiers such as com.ibm.team.workitem.common.query.SyntheticAttributeIdentifiers.TEAM_AREA_PROPERTY for the team area. Code for finding the work items associated to a team area based on the filed against categories can be found in com.ibm.team.reports.workitem.common.QueryUtils.createTeamAreaExpression(IAuditableCommon, IWorkItemCommon, IProjectArea, List, boolean) in the RTC SDK. The code shows:

       List expressions = new ArrayList(
                teamAreaHandles.size());
        IQueryableAttributeFactory factory = QueryableAttributes
                .getFactory(IWorkItem.ITEM_TYPE);
        IQueryableAttribute attribute = factory.findAttribute(projectArea,
                SyntheticAttributeIdentifiers.TEAM_AREA_PROPERTY,
                auditableCommon, new NullProgressMonitor());
        for (ITeamAreaHandle a : teamAreaHandles) {
            expressions.add(new AttributeExpression(attribute,
                    AttributeOperation.TEAM_AREA_EQUALS, a));
        }
        Expression expression = new Term(Term.OR,
                expressions.toArray(new Expression[expressions.size()]));

There is more interesting code in this utility class that you want to have a look at.

32 thoughts on “Using Expressions for Automation

  1. Pingback: Using an Expression to Synchronize Attributes for Work Items of a Specific Type | rsjazz

  2. Hi Ralph,

    Great post. Would it be possible to tell me how I could create query which filters by “ID”

    Ex: I want to Query “Task” by “ID”

    IS this possible with the Expressions?..

    Thanks in advance
    KK

  3. This is possible. If you follow the pattern of the expressions, this code does look for the ID (provided as a string workitemID). Since the ID is an integer type attribute, the string is converted to an int value.

    IQueryableAttribute idAttribute = QueryableAttributes.getFactory(
    IWorkItem.ITEM_TYPE).findAttribute(projectArea,
    IWorkItem.ID_PROPERTY, auditableCommon, monitor);
    Expression hasID = new AttributeExpression(idAttribute,
    AttributeOperation.EQUALS, new Integer(workitemID).intValue());

    • Hi Ralph,
      Thanks for sharing all the information, it helped a lot to folks like me.
      Question: I’m trying to fetch work-items based on ID and download the attachments and do some further processing, I achieved that with single ID, can you suggest how can I get multiple items at a time like ID is one of ( 123,456,789, …… ). I will then store them in some Data structure and download the attachments one by one ( Or is it possible to download all attachments for all ID’s at once as well, just a thought ?? )
      I do not want to put this in a loop for one ID at a time to avoid unnecessary calls to RTC. As of now I have put it in a loop for the # of ID’s and it is working fine, but I wish I could enhance my code.
      Thanks a lot !!!

  4. Hi Ralph, Sorry one more question..How can query custom attributes using the above query? Obviously they are’t part of the IWorkItem

  5. I would suggest to really look at the Java Calls. That easily reveals you basically need to pass the ID of the attribute to create an attribute expression. It does not matter if the attribute is built in. Here an example:

    IQueryableAttribute customAttribute = QueryableAttributes.getFactory(
    IWorkItem.ITEM_TYPE).findAttribute(projectArea,
    “com.company.wi.attrib.estimatedeffort”, auditableCommon, monitor);
    Expression contains = new AttributeExpression(customAttribute,
    AttributeOperation.CONTAINING, “1234”);

    Term findItem = new Term(Term.Operator.AND);
    findItem.add(contains);

    • Hi Ralph! I´ve tryed almost everything, but I always receive ItemNotFoundException when I try to use custom attributes in my queries. Do you know anything that I can do? Thanks for your help! I´m trying “br.gov.serpro.alm.itemdetrabalho.atributo.codigo_servico”, it´s type it is String Medium.

      • As far as I can tell, custom attributes are no different to built in attributes. There is nothing I can do with this information.

      • Thank you so much for your response! In fact now I got it! I was making a mistake on my code!
        I was using like this:
        queryClient.getExpressionResults(null, typeinProjectArea);
        And now I´m doing like this:
        queryClient.getExpressionResults(area, typeinProjectArea);

        It seems when you don´t pass the area to the method, only works with standard attibutes, but when I passed the area, it worked like a charm! Thanks again!

      • Usually you can NOT pass null arguments. At least you have to check what the interface expects. Custom attributes are also only defined in the project area they are defined. The built in attributes might be a bit different, but I would not bet on it.

  6. Hi Ralph,
    Is it possible to query RTC like ascending order or Descending order? If yes can you forward sample snippet for. it will be very helpful

  7. Hi, I’ve been following a lot this site lately and I found something that is not covered (or found to be covered) in here or in the jazz forums/query dev guide: how to query work items with attachments programmatically? I have not found anything in the IWorkItem interface to point me out to anything that can say ‘Attachments’. Maybe using the IAttachment interface in the Queryable attribute, but I’m getting errors trying to use anything there.

    I know that the attribute expression should be something like this:
    AttributeExpression attachmentsExpression = new AttributeExpression(
    attachmentsAttribute, AttributeOperation.EXISTS);

    But the attachmentsAttribute (IQueryableAttribute) is incomplete. Have you tried to query work items with attachments before using the java plain APIs?

    Maybe the solution is easier than it looks like but wanted to check with you, in case this is a corner case not covered by the APIs.

    • Mac, I have not tried to query for attachments and I am not sure it can be done. I’d suggest to search the SDK for the code you created above and try to find places where this is used.

  8. Hi Ralph,
    thank you for your great post. I use your code in my actual application to list all WorkItems for each single project area. After listing the workItems, i have sort them (modified_property):

    Expression expression = new AttributeExpression(attribute, AttributeOperation.EQUALS, projectArea);
    SortCriteria[] sortCriteria= new SortCriteria[] { new SortCriteria(IWorkItem.MODIFIED_PROPERTY, true)};
    Statement statement = new Statement(new SelectClause(), (Expression)term, sortCriteria);
    IQueryResult<IResolvedResult> results = queryClient.getResolvedExpressionResults(projectArea, statement, IWorkItem.FULL_PROFILE);

    Because my query is about all workitems and if the projectarea have maybe a few thousands of items later, i want to create another expression to limit the query. What i mean is to append a second expression like the code below:

    Expression expression2 = new AttributeExpression(attribute, AttributeOperation.EQUALS, actualDate -2 months); //only a query about the last 60 days
    Term term = new Term(Operator.AND);
    term.add(expression);
    term.add(expression2);
    Statement statement = new Statement(new SelectClause(), (Expression)term, sortCriteria);
    IQueryResult<IResolvedResult> results = queryClient.getResolvedExpressionResults(projectArea, statement, IWorkItem.FULL_PROFILE);

    Another Idea is to limit the query only to 30 WorkItems, but i don’t know how.

    Best regards!

    • One thing to consider, there is a maximum limit of items and you can set the result size limit.

      Another consideration might be to add more qualifications to the expression to limit the results you get in the first place.

      There is only so much you can do in these cases.

  9. Hi Rsjazz,
    I am first time working with RTC and
    I am querying the defects from RTC project area but I am getting the 0 records

    below is my code,

    IAuditableClient auditableClient = (IAuditableClient) repository.getClientLibrary(IAuditableClient.class);

    IQueryClient queryClient = (IQueryClient) repository.getClientLibrary(IQueryClient.class);

    IQueryableAttribute attribute = QueryableAttributes.getFactory(IWorkItem.ITEM_TYPE).findAttribute(currProject, IWorkItem.PROJECT_AREA_PROPERTY, auditableClient, null);

    IAttributeVariable variable = new WorkItemTypeVariable(“defect”);

    System.out.println(variable.getDisplayName());

    Expression expression = new AttributeExpression(attribute, AttributeOperation.EQUALS, variable);

    IQueryResult<IResolvedResult> results = queryClient.getResolvedExpressionResults(currProject, expression, IWorkItem.FULL_PROFILE);

    System.out.println(results.getResultSize(monitor).getTotal());

    Please help me, what I did the wrong in above code.

    Thanks in advance.

  10. Hi Ralph,
    using the query editor in the Eclipse Client UI it is pretty straightforward to create a query for a given workitem type that has links to change sets (click “Type is X” and “Change sets exist”).

    The first part is like the “isType” Expression instance in your example above.
    However, what is the corresponding IQueryableAttribute (if at all) and Expression for the change set links? I found the fields EXISTS and LINK_EXISTS in class AttributeOperation, but how do I get the IQueryableAttribute for the operation?
    Cheers
    Gan

    • I don’t usually know those details and have to search for them like everyone else. Searching through who implements IQueryableAttribute I found com.ibm.team.workitem.common.expression.IQueryableLinkAttribute

      If you search for IQueryableLinkAttribute and how it is used, you might find it out. Sometimes you have to experiment a bit.

  11. Hi RsJazz
    I have to pass a planned for attribute to fetch all related Story in Jazz server using Queries. I am new to RTC. Can u help me to get out from this

    • Sorry, but this blog is meant to help users to help them selves especially to do the first steps . I can’t provide the code for every question, obviously.

      In your case you would need a queryable attribute for the Planned For attribute and you would have to provide a value to compare to. In addition you would need an operation to compare the input.

      Iterations are nasty, search my blog, there are several that show how to work with timelines and iterations.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.